package com.apestech.framework.xml.pub.core;

import java.util.List;

import com.apestech.framework.json.JSONOrder;
import com.apestech.framework.util.FileUtil;
import com.apestech.framework.xml.plugin.callback.ExecNodeCallback;
import com.apestech.framework.xml.pub.WriteXml;
import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.CDATA;
import org.dom4j.Element;
import org.dom4j.Text;

import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.util.StringFuncUtil;

/**
 * 针对Element元素做二次封装
 * @author hupo
 *
 */
public class ElementUtil  extends StringFuncUtil {
	
	private static final Logger logger = Logger.getLogger(ElementUtil.class);
	
	/**
	 * 设置节点的属性信息,没有会追加新属性
	 * @param node  Element
	 * @param id    String
	 * @param value String
	 */
	@SuppressWarnings("deprecation")
	public void setAttr(Element node, String id, String value){
		if(node.attributeValue(id)==null){
			node.addAttribute(id, value);
		} else {
			node.setAttributeValue(id, value);
		}
	}
	
	/**
	 * 设置节点的子节点信息,没有会追加新子节点
	 * @param node  Element
	 * @param id    String
	 * @param value String
	 */
	public void setElement(Element node, String id, String value){
		if(node.elementByID(id)==null){
			node.addElement(id).setText(value);  
		} else {
			node.elementByID(id).setText(value);
		}
	}
	
	/**
	 * 获取某个结点下指定ID的子结点
	 * @param node Element
	 * @param id   String
	 */
	public Element getNodebyId(Element node, String id){
		List<?> clist=node.content();
    	int clen=clist.size();
        for(int c=0;c<clen;c++){
        	String scalss=clist.get(c).getClass().getName();
        	if(scalss.equals("org.dom4j.tree.DefaultElement")){
        		Element eml=(Element) clist.get(c);
        		if(eml.getName().equals(id)){
        			return eml;
        		}
        	}
        }
        return null;
	}
	
	/**
	 * 删除节点所有信息包括本身
	 * @param node Element
	 */
	public void removeNode(Element node){
		node.getParent().remove(node);
	}
	
	/**
	 * 删除某个结点下指定ID的子结点
	 * @param node Element
	 * @param id   String
	 */
	public void removeNodebyId(Element node, String id){
		List<?> clist=node.content();
    	int clen=clist.size();
        for(int c=0;c<clen;c++){
        	String scalss=clist.get(c).getClass().getName();
        	if(scalss.equals("org.dom4j.tree.DefaultElement")){
        		Element eml=(Element) clist.get(c);
        		if(eml.getName().equals(id)){
        			removeNode(eml);
        			clen--;
        			c--;
        		}
        	}
        }
	}
	
	/**
	 * 删除某个结点下的某个属性
	 * @param node     Element
	 * @param attrname String
	 */
	public void removeAttr(Element node, String attrname){
		Attribute attr=node.attribute(attrname);
		node.remove(attr);
	}
	
	/**
	 * 将原结点下全部内容复制至目录结点中
	 * @param sourcenode Element
	 * @param targetnode Element
	 * @param boolattr   Boolean
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public void copyNode(Element sourcenode, Element targetnode, Boolean boolattr) throws Exception{
		if (sourcenode==null || targetnode==null) {  
			return;
		}
		if(boolattr){
			List<Attribute> list = sourcenode.attributes();
            for (Attribute attr : list) {
            	targetnode.addAttribute(attr.getName().trim(), attr.getValue().trim());
            }
		}
		List<?> clist=sourcenode.content();
        int clen=clist.size();
        for(int c=0;c<clen;c++){
        	String scalss=clist.get(c).getClass().getName();
        	if(scalss.equals("org.dom4j.tree.DefaultText")){
        		Text txt=(Text) clist.get(c);
        		String Str=txt.getText().trim();
        		if(!("").equals(Str)){
        			targetnode.addText(Str);
        		}
        	} else if(scalss.equals("org.dom4j.tree.DefaultElement")){
        		Element eml=(Element) clist.get(c);
        		Element seml=targetnode.addElement(eml.getName());
        		copyNode(eml,seml,true);
        	}
        }	
	}

	public JSONObject getNodeOrderAttr(Element node){
		if (node == null) {
			return null;
		}
		String sATTR="";
		List<Attribute> list = node.attributes();
		JSONObject map=null;
		for (Attribute attr : list) {
			if(map==null) map=new JSONObject();
			if(!("").equals(sATTR)){
				sATTR=sATTR+";";
			}
			sATTR=sATTR+attr.getName().trim();
			map.put(attr.getName().trim(), attr.getValue().trim());
		}
		if("sql".equals(node.getName())){
			String txt=node.getTextTrim();
			if(!"".equals(txt)){
				if(map==null) map=new JSONObject();
				map.put("sql", txt);
			}
		}
		return map;
	}
	
	/**
	 * 获取某个结点属性信息
	 * @param node    Element
	 * @param nodemap JSONObject
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public JSONObject getNodeAttr(Element node, JSONObject nodemap){
		if (node == null) {  
			return null;
		}
		String sATTR="";
		if(nodemap==null){
			nodemap=new JSONObject();
		}
        List<Attribute> list = node.attributes();
        JSONObject map=null; 
        for (Attribute attr : list) {
        	if(map==null){
        		map=new JSONObject();
        	}
        	if(!("").equals(sATTR)){
        		sATTR=sATTR+";";
        	}
        	sATTR=sATTR+attr.getName().trim();
        	map.put(attr.getName().trim(), attr.getValue().trim());
        }
        if(map!=null){
        	nodemap.put("attrNode", map);
        }
		return nodemap;
	}
	
	/**
	 * 获取某个结点属性信息
	 * @param node Element
	 * @return
	 */
	public JSONObject getNodeAttr(Element node){
		return getNodeAttr(node, null);
	}
	
	/**
	 * 获取某个结点所有子结点列表,内容为子结点对应的属性数据合集
	 * @param node Element
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public JSONArray getNodeAttrList(Element node){
		if(node==null){
			return null;
		}
		JSONArray alist=new JSONArray();
    	List<?> clist=node.content();
    	int clen=clist.size();
        for(int c=0;c<clen;c++){
        	JSONObject map=new JSONObject();
        	String scalss=clist.get(c).getClass().getName();
        	if(scalss.equals("org.dom4j.tree.DefaultElement")){
        		Element eml=(Element) clist.get(c);
            	List<Attribute> list = eml.attributes();
                for (Attribute attr : list) {
                	map.put(attr.getName().trim(), attr.getValue().trim());
                }
                alist.add(map);
        	}
        }
        return alist;
	}
	
	/**
	 * 获取某个结点所有子结点列表,注意子结点内容要求为ID+TEXT模式
	 * @param node Element
	 * @return
	 */
	public JSONArray getNodeList(Element node){
		if(node==null){
			return null;
		}
		JSONArray alist=new JSONArray();
    	List<?> clist=node.content();
    	int clen=clist.size();
        for(int c=0;c<clen;c++){
        	JSONObject map=new JSONObject();
        	String scalss=clist.get(c).getClass().getName();
        	if(scalss.equals("org.dom4j.tree.DefaultElement")){
        		Element eml=(Element) clist.get(c);
        		List<?> elist=eml.content();
        		int elen=elist.size();
        		for(int j=0;j<elen;j++){
        			String scalss1=elist.get(j).getClass().getName();
        			if(scalss1.equals("org.dom4j.tree.DefaultElement")){
        				Element zeml=(Element) elist.get(j);
        				map.put(zeml.getName().trim(), zeml.getTextTrim());
        			}
        		}
        		alist.add(map);
        	}
        }
        return alist;
	}
	
	/**
	 * 将XML中某个结点内容转换成JSON格式 YY标准格式,值以TEXT为主
	 * @param node Element
	 * @param map  JSONObject 调用初值null
	 * @param bnew boolean 调用初值true
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public JSONObject toJson(Element node,JSONObject map,boolean bnew) throws Exception{
		if (node==null) {  
			return null;
		}
		JSONObject amap=new JSONObject();
		JSONObject smap=new JSONObject();
		List<Attribute> list = node.attributes();
        for (Attribute attr : list) {
        	smap.put(attr.getName().trim(), attr.getValue().trim());
        }
        if(smap.getString("nodeName")!=null && !("").equals(smap.getString("nodeName"))){
        	map.put(node.getName().trim(), getNodeList(node));
        } else if("1".equals(smap.getString("sql"))){
        	String text=node.getTextTrim();
        	if(!("").equals(text)){
        		if(bnew){
    				amap.put(node.getName().trim(), text);
    			} else {
    				map.put(node.getName().trim(), text);
    			}
    		}
        } else {
        	List<?> clist=node.content();
            int clen=clist.size();
            for(int c=0;c<clen;c++){
            	String scalss=clist.get(c).getClass().getName();
            	if(scalss.equals("org.dom4j.tree.DefaultText")){
            		Text txt=(Text) clist.get(c);
            		String Str=txt.getText().trim();
            		if(!("").equals(Str)){
            			if(bnew){
            				amap.put(node.getName().trim(), Str);
            			} else {
            				map.put(node.getName().trim(), Str);
            			}
            			
            		}
            	} else if(scalss.equals("org.dom4j.tree.DefaultElement")){
            		Element eml=(Element) clist.get(c);
            		map.put(node.getName().trim(), toJson(eml,amap,false));
            	}
            }
        }
        return map;
	}
	
	/**
	 * 将XML中某个结点内容转换成XML模板专用的JSON格式
	 * @param node Element
	 * @param map  JSONObject 调用初值null
	 * @param bnew boolean 调用初值true
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public JSONObject getNodeAttrJson(Element node,JSONObject map,boolean bnew) throws Exception{
		if (node==null) {  
			return null;
		}
		if (map==null) {  
			map=new JSONObject();
		}
		JSONObject amap=new JSONObject();
		JSONObject smap=new JSONObject();
		List<Attribute> list = node.attributes();
        for (Attribute attr : list) {
        	smap.put(attr.getName().trim(), attr.getValue().trim());
        }
        
        boolean bformat=false;
        if(node.getParent()!=null){
        	if("format".equals(node.getParent().getName())){
        		bformat=true;
            }
        }
        
        if("1".equals(smap.getString("sql"))){
        	String text=node.getTextTrim();
        	if(!("").equals(text)){
    			if(bformat){
    				if(bnew){
        				amap.put(node.getName().trim(), text);
        			} else {
        				map.put(node.getName().trim(), text);
        			}
    			} else {
    				JSONObject mxmap=new JSONObject();
    				if(smap.size()>0){
    					mxmap.put("node_attr", smap);
    				}
        			mxmap.put("node_text", text);
        			if(bnew){
        				amap.put(node.getName().trim(), mxmap);
        			} else {
        				map.put(node.getName().trim(), mxmap);
        			}
    			}
    		}
        } else {
        	List<?> clist=node.content();
            int clen=clist.size();
            for(int c=0;c<clen;c++){
            	String scalss=clist.get(c).getClass().getName();
            	if("org.dom4j.tree.DefaultText".equals(scalss) || "org.dom4j.tree.DefaultCDATA".equals(scalss)){
            		String text="";
            		if("org.dom4j.tree.DefaultText".equals(scalss)){
            			text=((Text) clist.get(c)).getText().trim();
            		} else {
            			text=((CDATA) clist.get(c)).getText().trim();
            		}
            		if(!("").equals(text)){
            			if(bformat){
            				if(bnew){
                				amap.put(node.getName().trim(), text);
                			} else {
                				map.put(node.getName().trim(), text);
                			}
            			} else {
            				JSONObject mxmap=new JSONObject();
            				if(smap.size()>0){
            					mxmap.put("node_attr", smap);
            				}
                			mxmap.put("node_text", text);
                			if(bnew){
                				amap.put(node.getName().trim(), mxmap);
                			} else {
                				map.put(node.getName().trim(), mxmap);
                			}
            			}
            		}
            	} else if(scalss.equals("org.dom4j.tree.DefaultElement")){
            		Element eml=(Element) clist.get(c);
            		JSONObject mxmap=getNodeAttrJson(eml,amap,false);
        			if(smap.size()>0){
    					mxmap.put("node_attr", smap);
    				}
        			map.put(node.getName().trim(),mxmap);
            	}
            }
        }
        return map;
	}
	
	/**
	 * 将XML中某个结点内容转换成JSON格式 外部XML格式,值以属性值为主
	 * @param node Element
	 * @param map  JSONObject 调用初值null
	 * @param bnew boolean 调用初值true
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public JSONObject toJsonAttr(Element node,JSONObject map,boolean bnew) throws Exception{
		if (node==null) {  
			return null;
		}
		JSONObject amap=new JSONObject();
		JSONObject smap=new JSONObject();
		List<Attribute> list = node.attributes();
        for (Attribute attr : list) {
        	smap.put(attr.getName().trim(), attr.getValue().trim());
        }
        if(bnew){
			amap.put(node.getName(),smap);
		} else {
			map.put(node.getName(),smap);
		}
        
        if("1".equals(smap.getString("sql"))){
        	String text=node.getTextTrim();
        	if(!("").equals(text)){
        		if(bnew){
    				amap.put(node.getName().trim(), text);
    			} else {
    				map.put(node.getName().trim(), text);
    			}
    		}
        } else {
        	List<?> clist=node.content();
            int clen=clist.size();
            for(int c=0;c<clen;c++){
            	String scalss=clist.get(c).getClass().getName();
            	if(scalss.equals("org.dom4j.tree.DefaultElement")){
            		Element eml=(Element) clist.get(c);
            		map.put(node.getName().trim(), toJsonAttr(eml,amap,false));
            	}
            }
        }
        
        return map;
	}

	public Element getNode(Element root, Element node, String nodeName, String key){
		if(root!=null) return (Element) root.selectSingleNode(nodeName+"[@id='"+key+"']");
		else return null;
	}

	public void execSubChild(Element node, ExecNodeCallback execNodeCallback) throws Exception {
		String id=node.getName();
		int attrCount=node.attributeCount();
		List<?> nodelist=node.content();
		int count=nodelist.size();
		boolean flag=false;
		for(int i=0; i<count; i++){
			String scalss=nodelist.get(i).getClass().getName();
			if(scalss.equals("org.dom4j.tree.DefaultElement")){
				Element e=(Element) nodelist.get(i);
				if(attrCount==0){
					execNodeCallback.getNode(e,id+"."+e.getName(), getNodeAttr(e).getJSONObject("attrNode"), e.getTextTrim());
				} else execNodeCallback.getNode(e, e.getName(), getNodeAttr(e).getJSONObject("attrNode"), e.getTextTrim());
				flag=true;
			}
		}
		if(count==0 || !flag) execNodeCallback.getNode(node, id, getNodeAttr(node).getJSONObject("attrNode"), node.getTextTrim());
	}

	public String ElementToTxt(Element node) throws Exception {
		WriteXml xml=new WriteXml();
		xml.createXml();
		xml.getRoot().add(node);
		String filename=this.getUUID()+".xml";
		xml.writeXml(filename);
		String str= getFileString(filename);
		FileUtil.deleteFile(filename);
		return str;
	}

}
